﻿﻿﻿/*!
 * 中国电子口岸数据中心 卡控件 v1.2.1 JavaScript Library v1.2.1
 * http://www.chinaport.gov.cn
 * Date:2017年4月25日
 * LastModifyDate:2017年12月2日
 */
(function (window, document, navigator) {
    //默认连接类型
    var DefaultType = "iKey";
    //卡控件安装包下载地址;
    var installlerUrl;
    //卡控件端口(默认端口) 
    var port = 61231;

    //对象转Json
    var toJson = function (obj) {
        if (window.JSON) {
            return JSON.stringify(obj);
        } else {
            alert("JSON转换错误!");
            return null;
        }
    };

    //返回值Json转对象
    var jsonToObj = function (text) {
        //*
        if (window.JSON) {
            return JSON.parse(text);
        } else {
            return eval("(" + text + ")");
        }
        //*/
    };

    var getGuid = function () {
        var s4 = function () {
            return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
        };
        return (s4() + s4() + "-" + s4() + "-" + s4() + "-" + s4() + "-" + s4() + s4() + s4());
    };

    //计算数据分块
    var splitStrData = function (dataStr) {
        if (typeof dataStr !== "string") {
            throw new Error("数据类型错误");
        }
        var MaxLength = 120 * 1024;
        var byteCount = 0, p = 0;
        var rst = [];
        for (var i = 0; i < dataStr.length; i++) {
            var _escape = escape(dataStr.charAt(i));
            byteCount = byteCount + ((_escape.length >= 4 && _escape.charAt(0) === "%" && _escape.charAt(1) === "u")/*汉字*/ ? 3 : 1);
            if (byteCount > MaxLength - 3) {
                rst.push(dataStr.substring(p, i + 1));
                p = i + 1;
                byteCount = 0;
            }
        }
        if (p !== dataStr.length) {
            rst.push(dataStr.substring(p));
        }
        return rst;
    };

    //"BLOCKTXT"+总校验码(4字节)+块校验码(4字节)+数据总大小(16字节)+当前块大小(8字节)+是否分块/分为几块(4字节)+数据分块组号(36字节)+数据包号(4字节)+保留位(44字节),总计128字长
    //        8               12              16                 32                40                       44                   80              84            128
    var getDataHeader = function (checkCode, blockCheckCode, size, currsize, blockCount, blockGuid, blockNum) {
        var rst = "BLOCKTXT";//8
        rst += equilongString(checkCode, 4, "0");//4
        rst += equilongString(blockCheckCode, 4, "0");//4
        rst += equilongString(size, 16, "0");//16
        rst += equilongString(currsize, 8, "0");//8
        rst += equilongString(blockCount, 4, "0");//4
        rst += equilongString(blockGuid, 36, "0");//36
        rst += equilongString(blockNum, 4, "0");//4
        rst += "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";//128个占位符0
        return rst.substring(0, 128);//截取前128个子
    };

    //获取等长字符串,默认补0
    var equilongString = function (str, length, prefix) {
        if (!str) {
            str = "";
        }
        if (typeof str !== "string") {
            str = str + "";
        }
        if (!prefix) {
            prefix = "0";
        }
        var diff = length - str.length;
        for (var i = 0; i < diff; i++) {
            str = prefix + str;
        }
        return str;
    };

    //判断IE
    var isIE6789 = function () {
        var version = (!!navigator.appVersion) ? navigator.appVersion.split(";") : [];
        var trim_Version = (version.length > 1) ? version[1].replace(/[ ]/g, "") : "";
        return navigator.appName === "Microsoft Internet Explorer" && (trim_Version === "MSIE6.0" || trim_Version === "MSIE7.0" || trim_Version === "MSIE8.0" || trim_Version === "MSIE9.0");
    };

    //IE6789,创建WebSocket对象
    if (!window.WebSocket && isIE6789()) {
        //alert("IE~");
        WebSocket = function (url) {
            this.activeXObject = new ActiveXObject("snsoft.WebSocket");
            var _self = this, ax = this.activeXObject;
            setTimeout(function () {
                ax.websocketOpen(_self, url);
            }, 0);
        };
        WebSocket.prototype = {
            _callback: function (call, ev) {
                var f;
                if (typeof (f = this[call]) === "function") {
                    f.call(this, ev);
                }
            },
            getReadyState: function (type) {
                return this.activeXObject.getReadyState((type || DefaultType));
            },
            send: function (data) {
                this.activeXObject.websocketSendText(data);
            },
            close: function () {
                this.activeXObject.websocketClose();
            }
        };
    }

    //连接本地服务
    var ws;
    var conn = function () {
        //readyState->0:尚未建立连接;1:已经建立连接;2:正在关闭;3:已经关闭或不可用
        //=0的时候不要创建新的了,连接慢的情况下,创建新的可能会更慢!
        if (!ws || getWebSocketReadyState(ws) === 2 || getWebSocketReadyState(ws) === 3) {
            var hostname = 'wss.singlewindow.cn';//'testlocal.sino-clink.com.cn';
            //最后方案:先试图连接wss协议,如果2秒后状态没有变化,则试图连接ws协议~
            try {
                ws = new WebSocket("wss://" + hostname + ":" + port);
                //启动计时器,3秒后判断状态,连接ws协议...
                //var timeTask = setTimeout(function(){
                //	if(!ws||getWebSocketReadyState(ws)==0||getWebSocketReadyState(ws)==3){
                //		ws= new WebSocket("ws://"+hostname+":"+port);
                //		ws.onmessage = function (e) {
                //			if (e.data.charAt(0)=="{") {
                //				var msg = jsonToObj(e.data);
                //				if (callbacks[msg["_method"]]) {
                //					callbacks[msg["_method"]](msg["_args"], e.data);
                //				}
                //			} else {
                //				alert("数据格式非法:" + e.data);
                //			}
                //		};
                //	}
                //},3000);
                //WebSocket事件
                ws.onmessage = function (e) {
                    if (e.data.charAt(0) === "{") {
                        var msg = jsonToObj(e.data);
                        //if(msg&&msg['_method']=="open"){
                        //握手成功,停掉timeTask的Task
                        //	clearTimeout(timeTask);
                        //}
                        if (callbacks[msg["_method"]]) {
                            callbacks[msg["_method"]](msg["_args"], e.data);
                        }
                    } else {
                        alert("数据格式非法:" + e.data);
                    }
                };
            } catch (ex) {
                if (console && console.log) {
                    console.log(ex);
                }
            }
        }
        return ws;
    };

    ws = conn();

    //setInterval(conn,10000);//每10秒检查一次

    //回调函数集合
    var callbacks = {};

    //分块数据{guid:{checkcode:"98AC",totalLength:14571,retry:0,block:[data1,data2,data3,...]},...}
    var blockData = {};


    var sendMessage = function (msg, callback) {
        if (getWebSocketReadyState(ws) === 1) {
            ws.send(msg);
        } else {
            //如果状态为0
            var times = 0;
            var waitForWebSocketConn = function () {
                if (times > 9) {
                    //throw new Error("连接卡控件服务失败，请重试。");
                    callback({Result: false, Data: [], Error: ["错误60408:连接卡控件服务失败，请重试。"]});
                    conn();//重连
                } else {
                    if (getWebSocketReadyState(ws) === 0) {//试图等待500毫秒
                        setTimeout(
                            function () {
                                if (getWebSocketReadyState(ws) === 1) {
                                    ws.send(msg);
                                } else {
                                    times++;
                                    waitForWebSocketConn();
                                }
                            }, 500);
                    } else if (getWebSocketReadyState(ws) === 2 || getWebSocketReadyState(ws) === 3) {//试图重连
                        times++;
                        conn();//重连
                    }
                }
            };
            waitForWebSocketConn();
        }
    };

    //分块的回调函数args:{id:1,guid:"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",next:1,finish:false}
    callbacks._nextBlock = function (args) {
        var guid = args.Data[0]["guid"];
        if (args.Data[0]["finish"]) {
            //要从内存中释放掉这个数据
            if (blockData[guid]) {
                delete blockData[guid];
            }
        } else {
            //传输
            conn();
            var next = args.Data[0]["next"];
            var blockObj = blockData[guid];
            if (!args.Result) {//失败的
                var retry = blockObj["retry"] || 0;
                retry = retry + 1;
                blockObj["retry"] = retry;
                if (retry > blockObj.block.length * 3) {
                    //达到最大重试次数
                    alert("数据接收错误!");
                }
            }
            var currDate = blockObj.block[next];
            var blockCheckCode = DIGEST.CheckCode(currDate);
            var pakHeaser = getDataHeader(blockObj["checkcode"], blockCheckCode, blockObj["totalLength"], currDate.length, blockObj.block.length, guid, next);
            var msg = pakHeaser + currDate;
            sendMessage(msg);
            //alert(toJson(args));
        }
    };

    //一种简化的摘要校验码,相比于CRC,对汉字的编码做的简化的处理.
    var DIGEST = {};
    DIGEST._auchCRCHi = [
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
        0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
        0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
        0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
        0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
        0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
        0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
        0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
        0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
        0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
        0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
        0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
        0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
        0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
        0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
        0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
        0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
        0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
        0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
        0x80, 0x41, 0x00, 0xC1, 0x81, 0x40
    ];
    DIGEST._auchCRCLo = [
        0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06,
        0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD,
        0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,
        0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A,
        0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4,
        0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
        0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3,
        0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4,
        0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,
        0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29,
        0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED,
        0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
        0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60,
        0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67,
        0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,
        0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68,
        0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E,
        0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
        0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71,
        0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92,
        0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,
        0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B,
        0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B,
        0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
        0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42,
        0x43, 0x83, 0x41, 0x81, 0x80, 0x40
    ];

    DIGEST.CheckCode = function (buffer) {
        var hi = 0xff;
        var lo = 0xff;
        for (var i = 0; i < buffer.length; i++) {
            var idx = 0xff & (hi ^ buffer.charCodeAt(i));
            hi = (lo ^ DIGEST._auchCRCHi[idx]);
            lo = DIGEST._auchCRCLo[idx];
        }
        return DIGEST.padLeft((hi << 8 | lo).toString(16).toUpperCase(), 4, '0');
    };
    DIGEST.padLeft = function (s, w, pc) {
        if (pc === undefined) {
            pc = '0';
        }
        for (var i = 0, c = w - s.length; i < c; i++) {
            s = pc + s;
        }
        return s;
    };

    var id = 0;

    //调用本地服务方法的抽象(数据不分包)
    var baseInvoke = function (method, args, callback) {
        if (typeof args === "function") {
            callback = args;
            args = {};
        }
        conn();
        callbacks[method] = callback;
        var _data = {"_method": method};
        _data["_id"] = id++;
        args = args || {};
        _data["args"] = args;
        var s = toJson(_data);
        if (getWebSocketReadyState(ws) === 0) {
            setTimeout(function () {
                //建立连接需要时间~ 首次延迟半秒~
                sendMessage(s, callback);
            }, 500)
        } else {
            sendMessage(s, callback);
        }
    };

    var baseInvokeByFrames = function (method, args, callback) {
        if (typeof args === "function") {
            callback = args;
            args = {};
        }
        conn();
        callbacks[method] = callback;
        var _data = {"_method": method};
        _data["_id"] = id++;
        args = args || {};
        _data["args"] = args;
        var s = toJson(_data);
        if (getWebSocketReadyState(ws) === 0 || getWebSocketReadyState(ws) === 3) {
            setTimeout(function () {
                //建立连接需要时间~ 首次延迟半秒~
                sendFrames(s, callback);
            }, 500)
        } else {
            sendFrames(s, callback);
        }
    };

    //分帧传输数据
    var sendFrames = function (s, callback) {
        //校验码
        var checkCode = DIGEST.CheckCode(s);//打校验码
        //分包的组
        var guid = getGuid();
        while (blockData[guid]) {
            //存在则重新生成一个!
            guid = getGuid();
        }
        //数据分块
        var splitData = splitStrData(s);//数据切块
        //记录以备重发
        blockData[guid] = {checkcode: checkCode, totalLength: s.length, retry: 0, block: splitData};
        //传第一个包
        //报头(纯文本类型)含义
        //"BLOCKTXT"+总校验码(4字节)+块校验码(4字节)+数据总大小(16字节)+当前块大小(8字节)+是否分块/分为几块(4字节)+数据分块组号(36字节)+数据包号(4字节)+保留位(44字节),总计128字长
        //        8               12              16                 32                40                       44                   80              84            128
        var blockCheckCode = DIGEST.CheckCode(splitData[0]);
        var pakHeaser = getDataHeader(checkCode, blockCheckCode, s.length, splitData[0].length, splitData.length, guid, 0);
        var msg = pakHeaser + splitData[0];
        sendMessage(msg, callback);
    };

    //readyState->0:尚未建立连接;1:已经建立连接;2:正在关闭;3:已经关闭或不可用
    var getWebSocketReadyState = function (thisWs) {
        var currWs = thisWs || conn();
        if (!currWs) {
            return 0;
        }
        if (currWs.readyState !== undefined) {
            return currWs.readyState;
        }
        if (currWs.getReadyState) {//IE8,IE9
            return currWs.getReadyState();
        }
        /*
         if(currWs.activeXObject){//IE8,IE9
         return currWs.activeXObject.readyState;
         }
         */
        return 0;
    };

    window.EportClient = {
        //更新调用
        update: function (callback) {
            conn();
            var method = "update";
            callbacks[method] = callback;
            var _data = {"_method": method};
            _data["_id"] = id++;
            _data["args"] = {};
            var s = toJson(_data);
            sendMessage(s);
        },
        isInstalled: function (type, callback, currInstalllerUrl) {
            //这个方法最慢需要3秒钟返回信息.
            if (typeof type === "function") {
                if (callback) {
                    currInstalllerUrl = callback;
                }
                callback = type;
                type = DefaultType;
            }
            ws = conn();
            var bInstalled = getWebSocketReadyState(ws) === 1;
            var retryConut = 0;

            function retry() {
                retryConut++;
                ws = conn();
                bInstalled = getWebSocketReadyState(ws) === 1;
                if (!bInstalled) {
                    if (retryConut <= 3) {
                        setTimeout(retry, 1500);
                    } else {
                        //未安装
                        var errMsg = "检测到您未安装" + type + "客户端,或者安装后没有重启计算机!,\n" + type + "下载地址为:" + currInstalllerUrl || installlerUrl || window.installlerUrl;
                        if (callback) {
                            callback({"Result": false, "Data": [], "Error": [errMsg]});
                        } else {
                            alert(errMsg);
                        }
                    }
                } else {
                    //已经安装了
                    var okMsg = "已经安装了" + type + "客户端.";
                    if (callback) {
                        callback({"Result": true, "Data": [okMsg], "Error": []});
                    } else {
                        alert(okMsg);
                    }
                }
            }

            retry();
            //iKeyInstalllerUrl
        },
        isInstalledTest: function (callback, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10) {//这里argX只多不少即可
            EportClient.isInstalled("iKey", function (msg) {
                if (msg.Result) {
                    if (callback && (typeof callback) === "function") {
                        callback.call(null, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10);
                    } else {
                        alert(msg.Data[0]);
                    }
                } else {
                    alertErrMsg(msg);
                }
            },"http://patchdownload.chinaport.gov.cn/IkeySetup/EportIkeySetup_V1.4.7.exe");
        },
        getfilepath: function (file, callback) {
            baseInvoke("getfilepath", {"file": file}, callback);
        },
        //下面是卡控件组件的调用接口
        login: function (passwd, callback) {
            baseInvoke("security_login", {"passwd": passwd}, callback);
        },

        signData: function (passwd, inputData, callback) {
            baseInvoke("security_signData", {"passwd": passwd, "inputData": inputData}, callback);
        },
        spcSignData: function (inData, callback) {
            baseInvoke("security_SpcSignData", {"inData": inData}, callback);
        },
        spcSignDataAsPEM: function (inData, callback) {
            baseInvoke("security_SpcSignDataAsPEM", {"inData": inData}, callback);
        },
        spcSignPemDataAsPEM: function (inData, callback) {
            baseInvoke("security_SpcSignPemDataAsPem", {"inData": inData}, callback);
        },
        spcSignDataNoHash: function (inData, callback) {
            baseInvoke("security_SpcSignDataNoHash", {"inData": inData}, callback);
        },
        spcSignDataNoHashAsPEM: function (inData, callback) {
            baseInvoke("security_SpcSignDataNoHashAsPEM", {"inData": inData}, callback);
        },
        spcVerifySignData: function (certDatePEM, inData, signData, callback) {
            baseInvoke("security_SpcVerifySignData", {
                "certDatePEM": certDatePEM,
                "inData": inData,
                "signData": signData
            }, callback);
        },
        spcVerifySignDataNoHash: function (certDatePEM, inData, signData, callback) {
            baseInvoke("security_SpcVerifySignDataNoHash", {
                "certDatePEM": certDatePEM,
                "inData": inData,
                "signData": signData
            }, callback);
        },
        spcSHA1Digest: function (szInfo, callback) {
            baseInvoke("security_SpcSHA1Digest", {"szInfo": szInfo}, callback);
        },
        spcSHA1DigestAsPEM: function (szInfo, callback) {
            baseInvoke("security_SpcSHA1DigestAsPEM", {"szInfo": szInfo}, callback);
        },
        spcSetInitEnvPriority: function (szInitEnvPriority, callback) {
            baseInvoke("security_SpcSetInitEnvPriority", {"szInitEnvPriority": szInitEnvPriority}, callback);
        },
        spcInitEnvEx: function (callback) {
            baseInvoke("security_SpcInitEnvEx", callback);
        },
        spcClearEnv: function (callback) {
            baseInvoke("security_SpcClearEnv", callback);
        },
        spcGetCardID: function (callback) {
            baseInvoke("security_SpcGetCardID", callback);
        },
        spcGetCertNo: function (callback) {
            baseInvoke("security_SpcGetCertNo", callback);
        },
        spcGetUName: function (callback) {
            baseInvoke("security_SpcGetUName", callback);
        },
        spcGetEntID: function (callback) {
            baseInvoke("security_SpcGetEntID", callback);
        },
        spcGetEntName: function (callback) {
            baseInvoke("security_SpcGetEntName", callback);
        },
        spcGetEntMode: function (callback) {
            baseInvoke("security_SpcGetEntMode", callback);
        },
        spcGetCardUserInfo: function (callback) {
            baseInvoke("security_SpcGetCardUserInfo", callback);
        },
        getGetCardUserInfoAll: function (userpin, callback) { //新增 by wlp 2017年11月15日,2017年11月29日 增加userpin
            if (!callback && typeof userpin === "function") {
                callback = userpin;
                userpin = null;
                baseInvoke("security_getGetCardUserInfoAll", {}, callback);
            } else {
                baseInvoke("security_getGetCardUserInfoAll", {"userpin": userpin}, callback);
            }
        },
        spcGetCardAttachInfo: function (callback) {
            baseInvoke("security_SpcGetCardAttachInfo", callback);
        },
        spcGetCardAttachInfoAsPEM: function (callback) {
            baseInvoke("security_SpcGetCardAttachInfoAsPEM", callback);
        },
        spcVerifyPIN: function (passwd, callback) {
            baseInvoke("security_SpcVerifyPIN", {"passwd": passwd}, callback);
        },
        spcChangePIN: function (oldPin, newPin, callback) {
            baseInvoke("security_SpcChangePIN", {"oldPin": oldPin, "newPin": newPin}, callback);
        },
        spcEncodePEM: function (inData, callback) {
            baseInvoke("security_SpcEncodePEM", {"inData": inData}, callback);
        },
        spcDecodePEM: function (inData, callback) {
            baseInvoke("security_SpcDecodePEM", {"inData": inData}, callback);
        },
        spcDecodePEMAsString: function (inData, callback) {
            baseInvoke("security_SpcDecodePEMAsString", {"inData": inData}, callback);
        },
        spcGetSignCert: function (callback) {
            baseInvoke("security_SpcGetSignCert", callback);
        },
        spcGetSignCertAsPEM: function (callback) {
            baseInvoke("security_SpcGetSignCertAsPEM", callback);
        },
        spcGetEnvCert: function (callback) {
            baseInvoke("security_SpcGetEnvCert", callback);
        },
        spcGetEnvCertAsPEM: function (callback) {
            baseInvoke("security_SpcGetEnvCertAsPEM", callback);
        },
        spcGetValidTimeFromCert: function (certByteArray, callback) {
            if (typeof certByteArray === "function") {
                callback = certByteArray;
                certByteArray = null;
            }
            baseInvoke("security_SpcGetValidTimeFromCert", ((!!certByteArray) ? {"certByteArray": certByteArray} : {}), callback);
        },
        spcGetValidTimeAll: function (callback) { //2017年11月01日 增加 by 王立鹏
            baseInvoke("security_getValidTimeAll", {}, callback);
        },
        spcSignRandom: function (passwd, random, callback) {
            baseInvoke("security_SpcSignRandom", {"passwd": passwd, "random": random}, callback);
        },
        pdfSignCheckSign: function (fileContent, callback) {
            baseInvokeByFrames("security_PdfSignCheckSign", {"fileContent": fileContent}, callback);
        },
        localPdfSignCheckSign: function (filePath, callback) {
            baseInvoke("security_PdfSignCheckSign", {"filePath": filePath}, callback);
        },
        pdfSignCheck: function (fileContent, callback) {
            baseInvokeByFrames("security_PdfSignCheck", {"fileContent": fileContent}, callback);
        },
        localPdfSignCheck: function (filePath, callback) {
            baseInvoke("security_PdfSignCheck", {"filePath": filePath}, callback);
        },
        pdfAddSign: function (fileContent, datetiem, Edoc_code, Edoc_Name, userpin, callback) {//destDir,fileName,
            //少1个参数,认为没传userpin,少两个,认为没传认为没传userpin和Edoc_Name,保证callback必须得有!
            if (callback && typeof callback === "function") {//完整参数
                baseInvokeByFrames("security_PdfAddSign", {
                    "fileContent": fileContent,
                    "datetiem": datetiem,
                    "Edoc_code": Edoc_code,
                    "Edoc_Name": Edoc_Name,
                    "userpin": userpin
                }, callback);
            } else if ((!callback) && typeof userpin === "function") {//缺少1个参数,我们兼容缺少userpin的情况
                callback = userpin;
                userpin = null;
                baseInvokeByFrames("security_PdfAddSign", {
                    "fileContent": fileContent,
                    "datetiem": datetiem,
                    "Edoc_code": Edoc_code,
                    "Edoc_Name": Edoc_Name
                }, callback);
            } else if ((!callback) && typeof Edoc_Name === "function") {//缺少1个参数,我们兼容缺少userpin的情况
                callback = Edoc_Name;
                Edoc_Name = null;
                baseInvokeByFrames("security_PdfAddSign", {
                    "fileContent": fileContent,
                    "datetiem": datetiem,
                    "Edoc_code": Edoc_code
                }, callback);
            } else {
                throw new Error("addSign的调用参数非法!");
                //alert("addSign的调用参数非法");
            }
        },
        localPdfAddSign: function (filePath, fileName, datetiem, Edoc_code, Edoc_Name, cookies, userpin, callback) {//destDir,fileName,
            //少1个参数,认为没传userpin;少2个,认为没传认为没传cookies和userpin;少3个,认为没传认为没传Edoc_Name/cookies和userpin.保证callback必须得有!
            if (callback && typeof callback === "function") {//完整参数
                baseInvoke("security_PdfAddSign", {
                    "filePath": filePath,
                    "fileName": fileName,
                    "datetiem": datetiem,
                    "Edoc_code": Edoc_code,
                    "Edoc_Name": Edoc_Name,
                    "cookies": cookies,
                    "userpin": userpin
                }, callback);
            } else if ((!callback) && typeof userpin === "function") {//缺少1个参数,我们兼容缺少userpin的情况
                callback = userpin;
                userpin = null;
                baseInvoke("security_PdfAddSign", {
                    "filePath": filePath,
                    "fileName": fileName,
                    "datetiem": datetiem,
                    "Edoc_code": Edoc_code,
                    "Edoc_Name": Edoc_Name,
                    "cookies": cookies
                }, callback);
            } else if ((!callback) && typeof cookies === "function") {//缺少2个参数,我们兼容缺少cookies和userpin的情况
                callback = cookies;
                cookies = null;
                baseInvoke("security_PdfAddSign", {
                    "filePath": filePath,
                    "fileName": fileName,
                    "datetiem": datetiem,
                    "Edoc_code": Edoc_code,
                    "Edoc_Name": Edoc_Name
                }, callback);
            } else if ((!callback) && typeof Edoc_Name === "function") {//缺少3个参数,我们兼容缺少Edoc_Name/cookies和userpin的情况
                callback = Edoc_Name;
                Edoc_Name = null;
                baseInvoke("security_PdfAddSign", {
                    "filePath": filePath,
                    "fileName": fileName,
                    "datetiem": datetiem,
                    "Edoc_code": Edoc_code
                }, callback);
            } else {
                throw new Error("addSign的调用参数非法!");
                //alert("addSign的调用参数非法");
            }
        },
        pdfCheckAndAddSign: function (fileContent, datetiem, Edoc_code, Edoc_Name, callback) {//destDir,fileName,
            //少1个参数,认为没传destDir,少两个,认为没传认为没传destDir和Edoc_Name,保证callback必须得有!
            if (callback && typeof callback === "function") {//完整参数
                baseInvokeByFrames("security_PdfCheckAndAddSign", {
                    "fileContent": fileContent,
                    "datetiem": datetiem,
                    "Edoc_code": Edoc_code,
                    "Edoc_Name": Edoc_Name
                }, callback);
            } else if ((!callback) && typeof Edoc_Name === "function") {//缺少1个参数,我们兼容缺少Edoc_Name的情况
                callback = Edoc_Name;
                Edoc_Name = null;
                baseInvokeByFrames("security_PdfCheckAndAddSign", {
                    "fileContent": fileContent,
                    "datetiem": datetiem,
                    "Edoc_code": Edoc_code
                }, callback);
            } else {
                throw new Error("addSign的调用参数非法!");
                //alert("addSign的调用参数非法");
            }
        },
        localPdfCheckAndAddSign: function (filePath, fileName, datetiem, Edoc_code, Edoc_Name, cookies, callback) {//destDir,fileName,
            //少1个参数,认为没传cookies,少两个,认为没传认为没传cookies和Edoc_Name,保证callback必须得有!
            if (callback && typeof callback === "function") {//完整参数
                baseInvoke("security_PdfCheckAndAddSign", {
                    "filePath": filePath,
                    "fileName": fileName,
                    "datetiem": datetiem,
                    "Edoc_code": Edoc_code,
                    "Edoc_Name": Edoc_Name,
                    "cookies": cookies
                }, callback);
            } else if ((!callback) && typeof cookies === "function") {//缺少1个参数,我们兼容缺少Edoc_Name的情况
                callback = cookies;
                cookies = null;
                baseInvoke("security_PdfCheckAndAddSign", {
                    "filePath": filePath,
                    "fileName": fileName,
                    "datetiem": datetiem,
                    "Edoc_code": Edoc_code,
                    "Edoc_Name": Edoc_Name
                }, callback);
            } else if ((!callback) && typeof Edoc_Name === "function") {//缺少2个参数,我们兼容缺少cookies和Edoc_Name的情况
                callback = Edoc_Name;
                Edoc_Name = null;
                baseInvoke("security_PdfCheckAndAddSign", {
                    "filePath": filePath,
                    "fileName": fileName,
                    "datetiem": datetiem,
                    "Edoc_code": Edoc_code
                }, callback);
            } else {
                throw new Error("addSign的调用参数非法!");
                //alert("addSign的调用参数非法");
            }
        },
        pdfScanInit: function (callback) {
            baseInvoke("security_PdfScanScanInitialize", {}, callback);
        },
        pdfScanAsPEM: function (Edoc_code, Edoc_Name, userpin, callback) {
            if (callback && typeof callback === "function") {//完整参数
                baseInvoke("security_PdfScanAsPEM", {
                    "Edoc_code": Edoc_code,
                    "Edoc_Name": Edoc_Name,
                    "userpin": userpin
                }, callback);
            } else if ((!callback) && typeof userpin === "function") {//缺少1个参数,我们兼容缺少userpin的情况
                callback = userpin;
                userpin = null;
                baseInvoke("security_PdfScanAsPEM", {
                    "Edoc_code": Edoc_code,
                    "Edoc_Name": Edoc_Name
                }, callback);
            } else if ((!callback) && typeof Edoc_Name === "function") {//缺少2个参数,我们兼容缺少userpin和Edoc_Name的情况
                callback = Edoc_Name;
                Edoc_Name = null;
                baseInvoke("security_PdfScanAsPEM", {"Edoc_code": Edoc_code}, callback);
            }
        },
        pdfScan: function (Edoc_code, Edoc_Name, userpin, callback) {
            if (callback && typeof callback === "function") {//完整参数
                baseInvoke("security_PdfScan", {
                    "Edoc_code": Edoc_code,
                    "Edoc_Name": Edoc_Name,
                    "userpin": userpin
                }, callback);
            } else if ((!callback) && typeof userpin === "function") {//缺少1个参数,我们兼容缺少userpin的情况
                callback = userpin;
                userpin = null;
                baseInvoke("security_PdfScan", {
                    "Edoc_code": Edoc_code,
                    "Edoc_Name": Edoc_Name
                }, callback);
            } else if ((!callback) && typeof Edoc_Name === "function") {//缺少2个参数,我们兼容缺少userpin和Edoc_Name的情况
                callback = Edoc_Name;
                Edoc_Name = null;
                baseInvoke("security_PdfScan", {"Edoc_code": Edoc_code}, callback);
            }
        },
        pdfView: function (fileContent, callback) {//destDir,fileName,
            baseInvokeByFrames("security_PdfView", {"fileContent": fileContent}, callback);
        },
        localPdfView: function (filePath, cookies, callback) {//filePath可以是本地的file:,也可以是http:的
            if (callback && typeof callback === "function") {//完整参数
                baseInvoke("security_PdfView", {"filePath": filePath, "cookies": cookies}, callback);
            } else if ((!callback) && typeof cookies === "function") {//缺少1个参数,我们兼容缺少title的情况
                callback = cookies;
                cookies = null;
                baseInvoke("security_PdfView", {"filePath": filePath}, callback);
            } else {
                throw new Error("addSign的调用参数非法!");
                alert("addSign的调用参数非法");
            }
        },
        localPdfBatchCheckAndSign: function (args, callback) {//args为js对象,不是json字符串!
            baseInvoke("security_LocalPdfBatchCheckAndSign", args, callback);
        },
        localPdfBatchUpload: function (args, callback) {
            baseInvoke("security_LocalPdfBatchUpload", args, callback);
        },
        deleteSignedTempFile: function (args, callback) {
            baseInvoke("security_DeleteSignedTempFile", args, callback);
        },

        //基础功能
        choosefile: function (filter, fileSize, callback) {
            if ((!callback) && (!fileSize) && typeof filter === "function") {
                callback = filter;
                filter = null;
                baseInvoke("base_choosefile", callback);
            } else if ((!callback) && typeof fileSize === "function") {
                callback = fileSize;
                fileSize = null;
                baseInvoke("base_choosefile", {"filter": filter}, callback);
            } else {
                baseInvoke("base_choosefile", {"filter": filter, "fileSize": fileSize}, callback);
            }
        },
        startClickOnceApp: function (qpurl, casurl, passwd, callback) {
            baseInvoke("base_StartClickOnceApp", {"qpurl": qpurl, "casurl": casurl, "passwd": passwd}, callback);
        },
        startClickOnceAppWithTicket: function (qpurl, callback) {
            if (!qpurl || qpurl === "") {
                callback({"Result": false, "Data": [], "Error": ["args中必须要包含必要的非空的qpurl参数!"]});
                return;
            } else if (qpurl.indexOf("ticket=") < 0 && qpurl.indexOf("ticket =") < 0) {
                callback({"Result": false, "Data": [], "Error": ["args中的qpurl必须要包含ticket!"]});
                return;
            }
            baseInvoke("base_StartClickOnceApp", {"qpurl": qpurl, "casurl": "-1", "passwd": "-1"}, callback);
        },
        startClickOnceAppWithUser: function (qpurl, callback) {
            baseInvoke("base_StartClickOnceAppWithUserinfo", {"qpurl": qpurl}, callback);
        },
        getLocalPrinters: function (callback) {
            baseInvoke("base_GetLocalPrinters", {}, callback);
        },
        setDefaultPrinter: function (printerName, callback) {
            baseInvoke("base_SetDefaultPrinter", {"printerName": printerName}, callback);
        },
        printPdf: function (fileContent, printerName, ranges, marginLeft, marginTop, milliseconds, callback) {
            if (callback && typeof callback === "function") {
                baseInvokeByFrames("base_PrintPdf", {
                    "fileContent": fileContent,
                    "printerName": printerName,
                    "ranges": ranges,
                    "marginLeft": marginLeft,
                    "marginTop": marginTop,
                    "milliseconds": milliseconds
                }, callback);
            } else if (!(callback) && typeof milliseconds === "function") {
                callback = milliseconds;
                milliseconds = null;
                baseInvokeByFrames("base_PrintPdf", {
                    "fileContent": fileContent,
                    "printerName": printerName,
                    "ranges": ranges,
                    "marginLeft": marginLeft,
                    "marginTop": marginTop
                }, callback);
            } else if (!(callback) && typeof marginTop === "function") {
                callback = marginTop;
                marginTop = null;
                baseInvokeByFrames("base_PrintPdf", {
                    "fileContent": fileContent,
                    "printerName": printerName,
                    "ranges": ranges,
                    "marginLeft": marginLeft,
                    "marginTop": 0
                }, callback);
            } else if (!(callback) && typeof marginLeft === "function") {
                callback = marginLeft;
                marginTop = null;
                marginLeft = null;
                baseInvokeByFrames("base_PrintPdf", {
                    "fileContent": fileContent,
                    "printerName": printerName,
                    "ranges": ranges,
                    "marginLeft": 0,
                    "marginTop": 0
                }, callback);
            } else if (!(callback) && typeof ranges === "function") {
                callback = ranges;
                marginTop = null;
                marginLeft = null;
                ranges = null;
                baseInvokeByFrames("base_PrintPdf", {
                    "fileContent": fileContent,
                    "printerName": printerName,
                    "marginLeft": 0,
                    "marginTop": 0
                }, callback);
            } else if (!(callback) && typeof printerName === "function") {
                callback = printerName;
                marginTop = null;
                marginLeft = null;
                ranges = null;
                printerName = null;
                baseInvokeByFrames("base_PrintPdf", {
                    "fileContent": fileContent,
                    "marginLeft": 0,
                    "marginTop": 0
                }, callback);
            } else {
                throw new Error("printPdf的调用参数非法!");
                alert("printPdf的调用参数非法");
            }
        },
        printLocalPdf: function (filePath, printerName, ranges, marginLeft, marginTop, milliseconds, callback) {
            if (callback && typeof callback === "function") {
                baseInvoke("base_PrintPdf", {
                    "filePath": filePath,
                    "printerName": printerName,
                    "ranges": ranges,
                    "marginLeft": marginLeft,
                    "marginTop": marginTop,
                    "milliseconds": milliseconds
                }, callback);
            } else if (!(callback) && typeof milliseconds === "function") {
                callback = milliseconds;
                milliseconds = null;
                baseInvoke("base_PrintPdf", {
                    "filePath": filePath,
                    "printerName": printerName,
                    "ranges": ranges,
                    "marginLeft": marginLeft,
                    "marginTop": marginTop
                }, callback);
            } else if (!(callback) && typeof marginTop === "function") {
                callback = marginTop;
                marginTop = null;
                baseInvoke("base_PrintPdf", {
                    "filePath": filePath,
                    "printerName": printerName,
                    "ranges": ranges,
                    "marginLeft": marginLeft,
                    "marginTop": 0
                }, callback);
            } else if (!(callback) && typeof marginLeft === "function") {
                callback = marginLeft;
                marginTop = null;
                marginLeft = null;
                baseInvoke("base_PrintPdf", {
                    "filePath": filePath,
                    "printerName": printerName,
                    "ranges": ranges,
                    "marginLeft": 0,
                    "marginTop": 0
                }, callback);
            } else if (!(callback) && typeof ranges === "function") {
                callback = ranges;
                marginTop = null;
                marginLeft = null;
                ranges = null;
                baseInvoke("base_PrintPdf", {
                    "filePath": filePath,
                    "printerName": printerName,
                    "marginLeft": 0,
                    "marginTop": 0
                }, callback);
            } else if (!(callback) && typeof printerName === "function") {
                callback = printerName;
                marginTop = null;
                marginLeft = null;
                ranges = null;
                printerName = null;
                baseInvoke("base_PrintPdf", {"filePath": filePath, "marginLeft": 0, "marginTop": 0}, callback);
            } else {
                throw new Error("printLocalPdf的调用参数非法!");
                //alert("printLocalPdf的调用参数非法");
            }
        },
        //下面是商务部的接口
        mofcomDetectKey: function (callback) {//判断是否插入了UKey
            baseInvoke("mofcom_DetectKey", {}, callback);
        },
        mofcomGetSelectedCertIndex: function (callback) {
            baseInvoke("mofcom_GetSelectedCertIndex", {}, callback);
        },
        mofcomListCertsNames: function (callback) {
            baseInvoke("mofcom_ListCertsNames", {}, callback);
        },
        mofcomSetSelectedCertIndex: function (index, callback) {
            baseInvoke("mofcom_SetSelectedCertIndex", {"index": index}, callback);
        },
        mofcomCheckUsbKeyPin: function (passwd, callback) {
            baseInvoke("mofcom_CheckUsbKeyPin", {"passwd": passwd}, callback);
        },
        mofcomGetEncodedCert: function (callback) {
            baseInvoke("mofcom_GetEncodedCert", {}, callback);
        },
        mofcomGetCertInfo: function (callback) {
            baseInvoke("mofcom_GetCertInfo", {}, callback);
        },
        mofcomSignMessage: function (message, callback) {
            baseInvoke("mofcom_SignMessage", {"message": message}, callback);
        },
        mofcomBatchSignMessage: function (messages, callback) {
            baseInvokeByFrames("mofcom_BatchSignMessage", {"messages": messages || []}, callback);
        },
        mofcomVerifyMsg: function (p7message, message, callback) {
            baseInvoke("mofcom_VerifyMsg", {"p7message": p7message, "message": message}, callback);
        },
        mofcomBatchVerifyMsg: function (p7messages, messages, callback) {
            baseInvokeByFrames("mofcom_BatchVerifyMsg", {
                "p7messages": p7messages || [],
                "messages": messages || []
            }, callback);
        },
        mofcomEnvelopedSignFile: function (inFile, callback) {
            baseInvoke("mofcom_EnvelopedSignFile", {"inFile": inFile}, callback);
        },
        mofcomEnvelopedVerifyFile: function (p7message, inFile, callback) {
            baseInvoke("mofcom_EnvelopedVerifyFile", {"p7message": p7message, "inFile": inFile}, callback);
        },
        //获取安装包版本号
        getInstallerVersion: function (callback) {
            baseInvoke("ver", callback);
        },
        //获取模块版本号
        getModuleVersion: function (module, callback) {
            baseInvoke(module + "_GetVersions", callback);
        },
        //下面是单一窗口组件的调用接口
        swcLogin: function (passwd, callback) {
            baseInvoke("swc_security_login", {"passwd": passwd}, callback);
        },
        swcPostData: function (data, callback, method) {
            conn();
            method = (method || "swc_postdata");
            callbacks[method] = callback;
            var _data = {"_method": method};
            _data["_id"] = id++;
            if (typeof data === "object") {
                _data["args"] = toJson(data);
            } else {
                _data["args"] = data;
            }
            var s = toJson(_data);
            //2016年10月27日 分块改为顺序传输
            //校验码
            var checkCode = DIGEST.CheckCode(s);
            //分包的组
            var guid = getGuid();
            while (blockData[guid]) {
                //存在则重新生成一个!
                guid = getGuid();
            }
            //数据分块
            var splitData = splitStrData(s);
            //如果需要分包传输
            if (splitData.length > 1) {
                blockData[guid] = {checkcode: checkCode, totalLength: s.length, retry: 0, block: splitData};
            }
            //传第一个包
            //报头(纯文本类型)含义
            //"BLOCKTXT"+总校验码(4字节)+块校验码(4字节)+数据总大小(16字节)+当前块大小(8字节)+是否分块/分为几块(4字节)+数据分块组号(36字节)+数据包号(4字节)+保留位(44字节),总计128字长
            //        8               12              16                 32                40                       44                   80              84            128
            var blockCheckCode = DIGEST.CheckCode(splitData[0]);
            var pakHeaser = getDataHeader(checkCode, blockCheckCode, s.length, splitData[0].length, splitData.length, guid, 0);
            var msg = pakHeaser + splitData[0];
            sendMessage(msg);
        },
        data: function () {
        }
    };
    //单一窗口组件调用..
    EportClient.data.prototype = {
        Execute: function (callback) {
            var d = toJson(this);
            EportClient.swcPostData(d, callback);
        }
    };
})(window, document, navigator);